<html>
<head>
<title>Online PHP Script Execution</title>
</head>
<body>
<?php
class Pattern {
  var $_label;
	var $_pattern;
	var $_selected;
	
	function Pattern ($l = "unknown"){
		$this->_selected =  false;
		$this->_label = $l;
		$this->_pattern = array();
	}

	function euclidean_distance (array $__pattern){		
		$dist = 0.0;
		for($i = 0; $i < count($this->_pattern); $i++){
			$dist += ($this->_pattern[$i] - $__pattern[$i]) * ($this->_pattern[$i] - $__pattern[$i]);
		
		}
		return sqrt($dist);
	}
	
	function move_to(array $__pattern, $e){
		for($i = 0; $i < count($this->_pattern); $i++)
			$this->_pattern[$i] += ($__pattern[$i] - $this->_pattern[$i]) * $e;
	}	

	function half_to(array $__pattern){
		$middle = new Pattern();
		for($i = 0; $i < count($this->_pattern); $i++)
			$middle->_pattern[] = ($__pattern[$i] + $this->_pattern[$i]) / 2;
		return $middle;
	}	
	
}

class Edge {
	var $weight;
	var $node_id;
	
	public function __construct ($id, $w = 0.0){
		$this->node_id = $id;
		$this->weight = $w;
	}
	
	public function printing () {
		echo '[' . $this->weight . ',' . $this->node_id . ']';
	}	
}


class Node {
	var 	$id;
	var 	$pattern;
	var 	$error;
	var		$edges;
	
	public function __construct (Pattern $pttrn, $i){
		$this->edges = array ();
		$this->pattern = $pttrn;
		$this->id = $i;
		$this->error = 0.0;
	}
	
	public function half_to(array $__pattern){
		return  $this->pattern->half_to($__pattern);
	}
	
	public function add_edge ($end_id, $edge_val){
		$edge = new Edge($end_id, $edge_val);
		$this->edges[] = $edge;
	}
	
	public function erase_edge($n2){
		for ($i = 0; $i < count($this->edges); $i++){
			if ($this->edges[$i]->node_id == $n2){
				unset($this->edges[$i]); 
        $this->edges = array_values($this->edges);
				break;
			}
		}		
	}
		
	public function remove_edges($limit){
		for ($i = 0; $i < count($this->edges); $i++){
			if ($this->edges[$i]->weight >= $limit){
				unset($this->edges[$i]); 
        $this->edges = array_values($this->edges);
			}
		}		
	}
	
	public function increase_local_error ($inc) {
		$this->error += $inc;
	}
	
	public function move_to (array $pattern, $eb){
		 $this->pattern->move_to($pattern, $eb);
	}
	
	public function printing (){
		echo "N: " . $this->id . "E:" . $this->error . '->';
    for ($i = 0; $i < count($this->edges); $i++){
			$this->edges[$i]->printing();
		}
		echo '</br>';
	}
}


class Graph {
	var $nodes;
	var $id_generator;
  var $clones;
	
	public function __construct () {
		$this->id_generator = 0;
		$this->nodes = array();
	}
	
	public function descrease_local_error($bt){
		for ($i = 0; $i < count($this->nodes); $i++){
			$this->nodes[$i]->error *= $bt;
		}
	}
	
	public function max_local_error (){
		$pos = 0; 
		$max = $this->nodes[0]->error;
		for ($i = 1; $i < count($this->nodes); $i++){
			if ($this->nodes[$i]->error > $max){
				$pos = $i;
				$max = $this->nodes[$i]->error;
			}
		}
		return $this->nodes[$pos]->id;
	}
	
	public function max_local_error_from ($id){
    $pos = $this->__find_position_node($id);
		$iterator = 0;
		$max = $this->nodes[$this->nodes[$pos]->edges[$iterator]->node_id]->error;
		for ($i = 1; $i < count($this->nodes[$pos]->edges); $i++){
			if ($this->nodes[$this->nodes[$pos]->edges[$i]->node_id]->error > $max){
				$iterator = $i;
				$max = $this->nodes[$this->nodes[$pos]->edges[$i]->node_id]->error;
			}
		}
		return $this->nodes[$pos]->edges[$iterator]->node_id;
	}
	
	public function erase_edge($id1, $id2){
    $n1 = $this->__find_position_node($id1);
    $n2 = $this->__find_position_node($id2);
		$this->nodes[$n1]->erase_edge($id2);
		$this->nodes[$n2]->erase_edge($id1);
	}
	
	public function increase_local_error ($id, $val) {
    $npos = $this->__find_position_node($id);
		$this->nodes[$npos]->increase_local_error($val);
	}
	
	public function add_node ($val){
		$idt = $this->id_generator;
		$node = new Node($val, $this->id_generator);
		$this->nodes[] = $node;
		$this->id_generator++;
		return $idt;
	}
	
	public function move_to ($id, array $pattern, $eb, $en){
     $pos = $this->__find_position_node($id);
		 $this->nodes[$pos]->move_to($pattern, $eb);
		 for ($i = 0; $i < count($this->nodes[$pos]->edges); $i++){
      $nid = $this->nodes[$pos]->edges[$i]->node_id;
      $npos = $this->__find_position_node($nid);    
			$this->nodes[$npos]->move_to($pattern,$en);
		 }	
	}
	
	public function remove_edges ($limit){
		for ($i = 0; $i < count($this->nodes); $i++){
			$this->nodes[$i]->remove_edges($limit);
			if (count($this->nodes[$i]->edges) ==  0) 
				unset ($this->nodes[$i]); // Posible conflicto en iteracion
        $this->nodes = array_values($this->nodes);   
		}
	}
	
	public function add_edge ($id1, $id2, $w = 0.0){
    $n1 = $this->__find_position_node($id1);
    $n2 = $this->__find_position_node($id2);
		$this->nodes[$n1]->add_edge($id2,$w);
		$this->nodes[$n2]->add_edge($id1,$w);
	}
	
	public function reset_edge ($id1, $id2, $w){
    $n1 = $this->__find_position_node($id1);
    $n2 = $this->__find_position_node($id2);
		for ($i = 0; $i < count($this->nodes[$n1]->edges); $i++){
			if ($this->nodes[$n1]->edges[$i]->node_id == $n2){
				$this->nodes[$n1]->edges[$i]->weight = $w;
				break;
			}
		}
		for ($i = 0; $i < count($this->nodes[$n2]->edges); $i++){
			if ($this->nodes[$n2]->edges[$i]->node_id == $n1){
				$this->nodes[$n2]->edges[$i]->weight = $w;
				break;
			}
		}
	}
	
	public function increase_edges_ages ($pos) {
    $npos = $this->__find_position_node($pos);
		for ($i = 0; $i < count($this->nodes[$npos]->edges); $i++){
			$this->nodes[$npos]->edges[$i]->weight++;
			$id = $this->nodes[$npos]->edges[$i]->node_id;
			for ($k = 0; $k < count ($this->nodes[$id]->edges); $k++){
				if ($this->nodes[$id]->edges[$k]->node_id == $pos){
					$this->nodes[$id]->edges[$k]->weight ++;
					break;
				}
			}
		}
	}
	
	public function exists_edge ($id1, $id2) {
    $n1 = $this->__find_position_node($id1);
    $n2 = $this->__find_position_node($id2);
		$exists = false;
		for ($i = 0; $i < count($this->nodes[$n1]->edges); $i++){
			if ($this->nodes[$n1]->edges[$i]->node_id == $n2)
				$exists = true;
		}
		return $exists;
	}
	
  public function clone_nodes(){
    $this->clones = $this->nodes;
  }
	
	public function find_nearest ($val){
		$iterator = 0;
		$distance = $this->clones[$iterator]->pattern->euclidean_distance($val);
		for ($pos = 1; $pos < count($this->clones); $pos++){
			$ndistance = $this->clones[$pos]->pattern->euclidean_distance($val);
			if ($ndistance < $distance) {
					$iterator = $pos;
					$distance = $ndistance;
			}
		}
    $res = $this->clones[$iterator]->id;
    unset ($this->clones[$iterator]);
    $this->clones = array_values($this->clones);
		return $res;
	}
	
	public function __find_position_node ($n){
		$pos = 0;
		for (; $pos < count($this->nodes); $pos++){
			if ($this->nodes[$pos]->id == $n) break;
		}
		return $pos;
	}

	
	public function printing () {
		for ($i = 0; $i < count ($this->nodes); $i++){
			$this->nodes[$i]->printing();
		}
	}
	
}


class Gng {
	var $_graph;
	var $_patterns;

	public function printing (){
		$this->_graph->printing();
	}
	
	public function __construct (){
		srand(time());
		$this->_graph = new Graph();
		$this->_patterns = array();
		
//		echo "Loading Source </br>";
		for($i = 0; $i < 100; $i++){
			$pattern = new Pattern("$i");
			for ($k = 0; $k < 5; $k++){
				$pattern->_pattern[] = rand (1,10);
			}
//			for ($k = 0; $k < count($pattern->_pattern); $k++)
//				echo  $pattern->_pattern[$k] . ' ';
//			echo '</br>';

			$this->_patterns[] = $pattern;			
		}
		
		$dimension = count($this->_patterns[0]->_pattern);
		$n1 =  new Pattern();
		$n2 =  new Pattern();
		for ($i = 0; $i < $dimension; $i++) {
			$n1->_pattern[] = rand(1,100);
			$n2->_pattern[] = rand(1,100);
		}
		$this->_graph->add_node ($n1);
		$this->_graph->add_node ($n2);
	}

	
	public function run ($t, $eb, $en, $limit, $lb, $lf, $bt){
    for ($k = 0; $k  < $t; $k++) {
      echo "Iteracion " . $k . '</br>'; 
  		for ($i = 0; $i < count($this->_patterns); $i++){
        $this->_graph->clone_nodes();
  			$n1 = $this->_graph->find_nearest($this->_patterns[$i]->_pattern);
      	$n2 = $this->_graph->find_nearest($this->_patterns[$i]->_pattern);
        $this->_graph->increase_edges_ages($n1);
  			$this->_graph->increase_local_error 
  				($n1, sqrt($this->_patterns[$i]->euclidean_distance(
  				$this->_graph->nodes[$n1]->pattern->_pattern)));
  			
  			$this->_graph->move_to($n1, $this->_patterns[$i]->_pattern, $eb, $en);
        
        if ($this->_graph->exists_edge($n1,$n2) ==  true) {
  				$this->_graph->reset_edge($n1, $n2, 0);
  			}else {
  				$this->_graph->add_edge($n1, $n2, 0);
  			}
        
  			$this->_graph->remove_edges($limit);
        
        if ($i % $lb == 0) {
  				$max = $this->_graph->max_local_error();
  				$smax = $this->_graph->max_local_error_from($max);
          $pmax = $this->_graph->__find_position_node($max);
          $psmax = $this->_graph->__find_position_node($smax);
          $val = $this->_graph->nodes[$pmax]->half_to($this->_graph->nodes[$psmax]->pattern->_pattern);
          $n3 = $this->_graph->add_node ($val);
        	$this->_graph->erase_edge($max,$smax); 
          $this->_graph->add_edge($max,$n3,0.0);
          $this->_graph->add_edge($n3,$smax,0.0);
          $this->_graph->nodes[$max]->error *= $lf;
          $this->_graph->nodes[$smax]->error *= $lf;
  				$this->_graph->nodes[$n3]->error = $this->_graph->nodes[$max]->error;
        }
  			$this->_graph->descrease_local_error($bt);
    	}
      $this->_graph->printing(); echo '</br>';
    }
	}

}
$gng =  new Gng();
$gng->printing();echo '</br>';
$gng->run (10, .5, .25, 10, 10, .5, .25);


?>
</body>
</html>
